#include <iostream>
#include <stdio.h>
#include <iomanip>
#include "GradientDescent.h"

using namespace std;
using std::vector;
using std::streamsize;
using std::setprecision;

GradientDescent::GradientDescent(LinearRegression * linReg, double thetaZero, double thetaOne, double learningRate)
{
	this->linReg = linReg;
	this->thetaZero = thetaZero;
	this->thetaOne= thetaOne;
	this->alpha = learningRate;

	linReg->SetThetas(thetaZero, thetaOne);
}

void GradientDescent::Calculate()
{
	cout << "J    Theta0   Theta1    d/dTheta0    d/dTheta1" << endl;
	cout << "==============================================" << endl;

	int count = 0;
	double j = 0, previousJ;
	do
	{
		previousJ = j;
		j = linReg->J();

		double descentStepZero = 0;
		for(int i = 0; i < linReg->M(); i++)
		{
			descentStepZero += linReg->h[i] - linReg->y[i];
		}
		descentStepZero /= linReg->M();

		thetaZero = thetaZero - alpha * descentStepZero;

		double descentStepOne = 0;
		for(int i = 0; i < linReg->M(); i++)
		{
			descentStepOne += linReg->h[i] - linReg->y[i] * linReg->x[i];
		}
		descentStepOne /= linReg->M();

		thetaOne = thetaOne - alpha * descentStepOne;

		streamsize prec = cout.precision();
		cout << setprecision(5) 
			<< j << " " 
			<< thetaZero << " " 
			<< thetaOne << " "
			<< descentStepZero << " "
			<< descentStepOne << " "
			<< setprecision(prec) << endl;

		linReg->SetThetas(thetaZero, thetaOne);
		count++;
	}
	//while(count < 500);
	while(previousJ == 0 || previousJ >= j);

}